import socket from '@ohos.net.socket';
import { log } from '../../util/index';

import type {
  TCPSocket,
  NetAddress,
  TCPConnectOptions,
  TCPSendOptions,
  TCPExtraOptions,
  SocketMessageInfo,
  SocketStateBase
} from './type'

const TAG = 'message_system'

export function createTCPInstance(): MyTCPSocket {
  try {
    const tcpSocket = socket.constructTCPSocketInstance()
    if (tcpSocket) {
      log.info(TAG, 'constructTCPSocketInstance success')
      return new MyTCPSocket(tcpSocket)
    }
    log.error(TAG, 'constructTCPSocketInstance fail', 'tcp instance is null')
    return null
  } catch (err) {
    log.error(TAG, 'constructTCPSocketInstance fail', JSON.stringify(err) ?? '')
    return null
  }
}

export class MyTCPSocket {
  private tcpSocket: TCPSocket;

  constructor(tcpSocket: TCPSocket) {
    this.tcpSocket = tcpSocket
  }

  async bind(address: NetAddress): Promise<boolean> {
    if (this.tcpSocket) {
      try {
        await this.tcpSocket.bind(address)
        log.info(TAG, 'MyTCPSocket bind success')
        return true
      } catch (err) {
        log.error(TAG, 'MyTCPSocket bind fail', JSON.stringify(err) ?? '')
        return false
      }
    } else {
      log.error(TAG, 'MyTCPSocket is null')
      return false
    }
  }

  async connect(options: TCPConnectOptions): Promise<boolean> {
    if (this.tcpSocket) {
      try {
        await this.tcpSocket.connect(options)
        log.info(TAG, 'MyTCPSocket connect success')
        return true
      } catch (err) {
        log.error(TAG, 'MyTCPSocket connect fail', JSON.stringify(err) ?? '')
        return false
      }
    } else {
      log.error(TAG, 'MyTCPSocket is null')
      return false
    }
  }

  async getState(): Promise<SocketStateBase> {
    if (this.tcpSocket) {
      try {
        const state = await this.tcpSocket.getState()
        log.info(TAG, 'MyTCPSocket getState success')
        return state
      } catch (err) {
        log.error(TAG, 'MyTCPSocket getState fail', JSON.stringify(err) ?? '')
        return null
      }
    } else {
      log.error(TAG, 'MyTCPSocket is null')
      return null
    }
  }

  async send(options: TCPSendOptions): Promise<boolean> {
    if (this.tcpSocket) {
      try {
        await this.tcpSocket.send(options)
        log.info(TAG, 'MyTCPSocket send success')
        return true
      } catch (err) {
        log.error(TAG, 'MyTCPSocket send fail', JSON.stringify(err) ?? '')
        return false
      }
    } else {
      log.error(TAG, 'MyTCPSocket is null')
      return false
    }
  }

  async close(): Promise<boolean> {
    if (this.tcpSocket) {
      try {
        await this.tcpSocket.close()
        log.info(TAG, 'MyTCPSocket close success')
        return true
      } catch (err) {
        log.error(TAG, 'MyTCPSocket close fail', JSON.stringify(err) ?? '')
        return false
      }
    } else {
      log.error(TAG, 'MyTCPSocket is null')
      return false
    }
  }

  setExtraOptions(options: TCPExtraOptions): boolean {
    if (this.tcpSocket) {
      try {
        this.tcpSocket.setExtraOptions(options)
        log.info(TAG, 'MyTCPSocket setExtraOptions success')
        return true
      } catch (err) {
        log.error(TAG, 'MyTCPSocket setExtraOptions fail', JSON.stringify(err) ?? '')
        return false
      }
    } else {
      log.error(TAG, 'MyTCPSocket is null')
      return false
    }
  }

  onMessage(handler: (value: SocketMessageInfo) => void): boolean {
    if (this.tcpSocket) {
      try {
        this.tcpSocket.on('message', handler)
        log.info(TAG, 'MyTCPSocket onMessage success')
        return true
      } catch (err) {
        log.error(TAG, 'MyTCPSocket onMessage fail', JSON.stringify(err) ?? '')
        return false
      }
    } else {
      log.error(TAG, 'MyTCPSocket is null')
      return false
    }
  }

  onConnect(handler: () => void): boolean {
    if (this.tcpSocket) {
      try {
        this.tcpSocket.on('connect', handler)
        log.info(TAG, 'MyTCPSocket onConnect success')
        return true
      } catch (err) {
        log.error(TAG, 'MyTCPSocket onConnect fail', JSON.stringify(err) ?? '')
        return false
      }
    } else {
      log.error(TAG, 'MyTCPSocket is null')
      return false
    }
  }

  onClose(handler: () => void): boolean {
    if (this.tcpSocket) {
      try {
        this.tcpSocket.on('close', handler)
        log.info(TAG, 'MyTCPSocket onClose success')
        return true
      } catch (err) {
        log.error(TAG, 'MyTCPSocket onClose fail', JSON.stringify(err) ?? '')
        return false
      }
    } else {
      log.error(TAG, 'MyTCPSocket is null')
      return false
    }
  }

  onError(handler: () => void): boolean {
    if (this.tcpSocket) {
      try {
        this.tcpSocket.on('error', handler)
        log.info(TAG, 'MyTCPSocket onError success')
        return true
      } catch (err) {
        log.error(TAG, 'MyTCPSocket onError fail', JSON.stringify(err) ?? '')
        return false
      }
    } else {
      log.error(TAG, 'MyTCPSocket is null')
      return false
    }
  }
}